package com.stony.reactor;

import java.nio.charset.Charset;

/**
 * <p>reactorDome
 * <p>com.stony.reactor
 *
 * @author stony
 * @version 下午2:09
 * @since 2018/1/9
 */
public class SimpleByteBuffer {
    /**
     * Default initial capacity.
     */
    static final int DEFAULT_CAPACITY = 64;
    public static final Charset UTF8_CHARSET = Charset.forName("UTF-8");

    byte[] data;
    int offset = 0;
    int readIndex = 0;

    public SimpleByteBuffer() {
        this(DEFAULT_CAPACITY);
    }
    public SimpleByteBuffer(int initialCapacity) {
        this.data = new byte[initialCapacity];
    }

    /**
     * 一个字节
     * @param value
     * @return
     */
    public SimpleByteBuffer writerByte(byte value){
        int pos = this.offset;
        if (pos + 1 > data.length) {
            enlarge(1);
        }
        byte[] _data = this.data;
        _data[pos++] = value;
        this.offset = pos;
        return this;
    }

    /**
     * 写入2个字节
     * @param value
     * @return
     */
    public SimpleByteBuffer writerShort(short value){
        int pos = this.offset;
        if (pos + 2 > data.length) {
            enlarge(2);
        }
        byte[] _data = this.data;
        _data[pos++] = (byte) (value >>> 8);
        _data[pos++] = (byte) value;
        this.offset = pos;
        return this;
    }
    /**
     * 写入4个字节
     * @param value
     * @return
     */
    public SimpleByteBuffer writerInt(int value){
        int pos = this.offset;
        if (pos + 4 > data.length) {
            enlarge(4);
        }
        byte[] _data = this.data;
        _data[pos++] = (byte) (value >>> 24);
        _data[pos++] = (byte) (value >>> 16);
        _data[pos++] = (byte) (value >>> 8);
        _data[pos++] = (byte) value;
        this.offset = pos;
        return this;
    }
    /**
     * 写入8个字节
     * @param value
     * @return
     */
    public SimpleByteBuffer writerLong(long value){
        int pos = this.offset;
        if (pos + 8 > data.length) {
            enlarge(8);
        }
        byte[] _data = this.data;
        _data[pos++] = (byte) (value >>> 56);
        _data[pos++] = (byte) (value >>> 48);
        _data[pos++] = (byte) (value >>> 40);
        _data[pos++] = (byte) (value >>> 32);
        _data[pos++] = (byte) (value >>> 24);
        _data[pos++] = (byte) (value >>> 16);
        _data[pos++] = (byte) (value >>> 8);
        _data[pos++] = (byte) value;
        this.offset = pos;
        return this;
    }
    public SimpleByteBuffer writerBytes(byte[] value){
        int pos = this.offset;
        int len = value.length;
        if (pos + len > data.length) {
            enlarge(len);
        }
        byte[] _data = this.data;
        System.arraycopy(value, 0, _data, pos, len);
        pos += len;
        this.offset = pos;
        return this;
    }
    public SimpleByteBuffer writerUTF8(String value) {
        return writerBytes(value.getBytes(UTF8_CHARSET));
    }

    public byte readByte(){
        int pos = (this.readIndex);
        this.readIndex = pos+1;
        byte[] _data = this.data;
        return _data[pos--];
    }

    /**
     * 读取2个字节
     * @return
     */
    public short readShort(){
        int pos = (this.readIndex + 1);
        this.readIndex = pos+1;
        byte[] _data = this.data;
        return (short) (_data[pos--] & 0xFF | (_data[pos--] & 0xFF) << 8);
    }
    /**
     * 读取4个字节
     * @return
     */
    public int readInt(){
        int pos = (this.readIndex + 3);
        this.readIndex = pos+1;
        byte[] _data = this.data;
        return _data[pos--] & 0xFF |
                (_data[pos--] & 0xFF) << 8 |
                (_data[pos--] & 0xFF) << 16 |
                (_data[pos--] & 0xFF) << 24;
    }
    /**
     * 读取8个字节
     * @return
     */
    public long readLong(){
        int pos = (this.readIndex + 7);
        this.readIndex = pos+1;
        byte[] _data = this.data;
        return _data[pos--] & 0xFFL |
                (_data[pos--] & 0xFFL) << 8 |
                (_data[pos--] & 0xFFL) << 16 |
                (_data[pos--] & 0xFFL) << 24 |
                (_data[pos--] & 0xFFL) << 32 |
                (_data[pos--] & 0xFFL) << 40 |
                (_data[pos--] & 0xFFL) << 48 |
                (_data[pos--] & 0xFFL) << 56;
    }
    public String readUTF8(int len){
        return new String(readBytes(len), UTF8_CHARSET);
    }
    public byte[] readBytes(int len){
        int pos = this.readIndex;
        byte[] _data = this.data;
        byte[] result = new byte[len];
        System.arraycopy(_data, pos, result, 0, len);
        pos += len;
        this.readIndex = pos;
        return result;
    }
    void enlarge(final int size) {
        int newLen = this.data.length * 2;
        int newLen2 = this.offset + size;
        byte[] newData = new byte[newLen > newLen2 ? newLen : newLen2];
        System.arraycopy(this.data, 0, newData, 0, this.offset);
        this.data = newData;
    }
    /** 数据包长度 **/
    public int getLength() {
        return this.offset;
    }
    /** 偏移量位置 **/
    public int size(){
        return this.offset;
    }
    public byte[] getData() {
        return this.data;
    }
    public void clear(){
        this.offset = 0;
        this.data = new byte[DEFAULT_CAPACITY];
    }
    /** 重置读写指针 **/
    public void restOffset(){
        this.offset = 0;
        this.readIndex = 0;
    }
}
